home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / src / binutils.252 / gas / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-13  |  27.6 KB  |  965 lines

  1. /* hash.c - hash table lookup strings -
  2.    Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.  
  4.    This file is part of GAS, the GNU Assembler.
  5.  
  6.    GAS is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    GAS is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with GAS; see the file COPYING.  If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * BUGS, GRIPES, APOLOGIA etc.
  22.  *
  23.  * A typical user doesn't need ALL this: I intend to make a library out
  24.  * of it one day - Dean Elsner.
  25.  * Also, I want to change the definition of a symbol to (address,length)
  26.  * so I can put arbitrary binary in the names stored. [see hsh.c for that]
  27.  *
  28.  * This slime is common coupled inside the module. Com-coupling (and other
  29.  * vandalism) was done to speed running time. The interfaces at the
  30.  * module's edges are adequately clean.
  31.  *
  32.  * There is no way to (a) run a test script through this heap and (b)
  33.  * compare results with previous scripts, to see if we have broken any
  34.  * code. Use GNU (f)utilities to do this. A few commands assist test.
  35.  * The testing is awkward: it tries to be both batch & interactive.
  36.  * For now, interactive rules!
  37.  */
  38.  
  39. /*
  40.  *  The idea is to implement a symbol table. A test jig is here.
  41.  *  Symbols are arbitrary strings; they can't contain '\0'.
  42.  *    [See hsh.c for a more general symbol flavour.]
  43.  *  Each symbol is associated with a char*, which can point to anything
  44.  *  you want, allowing an arbitrary property list for each symbol.
  45.  *
  46.  *  The basic operations are:
  47.  *
  48.  *    new                     creates symbol table, returns handle
  49.  *    find (symbol)           returns char*
  50.  *    insert (symbol,char*)   error if symbol already in table
  51.  *    delete (symbol)         returns char* if symbol was in table
  52.  *    apply                   so you can delete all symbols before die()
  53.  *    die                     destroy symbol table (free up memory)
  54.  *
  55.  *  Supplementary functions include:
  56.  *
  57.  *    say                     how big? what % full?
  58.  *    replace (symbol,newval) report previous value
  59.  *    jam (symbol,value)      assert symbol:=value
  60.  *
  61.  *  You, the caller, have control over errors: this just reports them.
  62.  *
  63.  *  This package requires malloc(), free().
  64.  *  Malloc(size) returns NULL or address of char[size].
  65.  *  Free(address) frees same.
  66.  */
  67.  
  68. /*
  69.  *  The code and its structures are re-enterent.
  70.  *
  71.  *  Before you do anything else, you must call hash_new() which will
  72.  *  return the address of a hash-table-control-block.  You then use
  73.  *  this address as a handle of the symbol table by passing it to all
  74.  *  the other hash_...() functions.  The only approved way to recover
  75.  *  the memory used by the symbol table is to call hash_die() with the
  76.  *  handle of the symbol table.
  77.  *
  78.  *  Before you call hash_die() you normally delete anything pointed to
  79.  *  by individual symbols. After hash_die() you can't use that symbol
  80.  *  table again.
  81.  *
  82.  *  The char* you associate with a symbol may not be NULL (0) because
  83.  *  NULL is returned whenever a symbol is not in the table. Any other
  84.  *  value is OK, except DELETED, #defined below.
  85.  *
  86.  *  When you supply a symbol string for insertion, YOU MUST PRESERVE THE
  87.  *  STRING until that symbol is deleted from the table. The reason is that
  88.  *  only the address you supply, NOT the symbol string itself, is stored
  89.  *  in the symbol table.
  90.  *
  91.  *  You may delete and add symbols arbitrarily.
  92.  *  Any or all symbols may have the same 'value' (char *). In fact, these
  93.  *  routines don't do anything with your symbol values.
  94.  *
  95.  *  You have no right to know where the symbol:char* mapping is stored,
  96.  *  because it moves around in memory; also because we may change how it
  97.  *  works and we don't want to break your code do we? However the handle
  98.  *  (address of struct hash_control) is never changed in
  99.  *  the life of the symbol table.
  100.  *
  101.  *  What you CAN find out about a symbol table is:
  102.  *    how many slots are in the hash table?
  103.  *    how many slots are filled with symbols?
  104.  *    (total hashes,collisions) for (reads,writes) (*)
  105.  *  All of the above values vary in time.
  106.  *  (*) some of these numbers will not be meaningful if we change the
  107.  *  internals. */
  108.  
  109. /*
  110.  *  I N T E R N A L
  111.  *
  112.  *  Hash table is an array of hash_entries; each entry is a pointer to a
  113.  *  a string and a user-supplied value 1 char* wide.
  114.  *
  115.  *  The array always has 2 ** n elements, n>0, n integer.
  116.  *  There is also a 'wall' entry after the array, which is always empty
  117.  *  and acts as a sentinel to stop running off the end of the array.
  118.  *  When the array gets too full, we create a new array twice as large
  119.  *  and re-hash the symbols into the new array, then forget the old array.
  120.  *  (Of course, we copy the values into the new array before we junk the
  121.  *  old array!)
  122.  *
  123.  */
  124.  
  125. #include <stdio.h>
  126.  
  127. #ifndef FALSE
  128. #define FALSE    (0)
  129. #define TRUE    (!FALSE)
  130. #endif /* no FALSE yet */
  131.  
  132. #include <ctype.h>
  133. #define min(a, b)    ((a) < (b) ? (a) : (b))
  134.  
  135. #include "as.h"
  136.  
  137. #define error    as_fatal
  138.  
  139. #define DELETED     ((PTR)1)    /* guarenteed invalid address */
  140. #define START_POWER    (11)    /* power of two: size of new hash table */
  141.  
  142. /* TRUE if a symbol is in entry @ ptr.  */
  143. #define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED)
  144.  
  145. /* Number of slots in hash table.  The wall does not count here.
  146.    We expect this is always a power of 2.  */
  147. #define STAT_SIZE      (0)
  148. #define STAT_ACCESS    (1)    /* number of hash_ask()s */
  149. #define STAT__READ     (0)    /* reading */
  150. #define STAT__WRITE    (1)    /* writing */
  151. /* Number of collisions (total).  This may exceed STAT_ACCESS if we
  152.    have lots of collisions/access.  */
  153. #define STAT_COLLIDE   (3)
  154. #define STAT_USED      (5)    /* slots used right now */
  155. #define STATLENGTH     (6)    /* size of statistics block */
  156. #if STATLENGTH != HASH_STATLENGTH
  157. Panic! Please make #include "stat.h" agree with previous definitions!
  158. #endif
  159.  
  160. /* #define SUSPECT to do runtime checks */
  161. /* #define TEST to be a test jig for hash...() */
  162.  
  163. #ifdef TEST
  164. /* TEST: use smaller hash table */
  165. #undef  START_POWER
  166. #define START_POWER (3)
  167. #undef  START_SIZE
  168. #define START_SIZE  (8)
  169. #undef  START_FULL
  170. #define START_FULL  (4)
  171. #endif
  172.  
  173. /*------------------ plan ---------------------------------- i = internal
  174.  
  175.   struct hash_control * c;
  176.   struct hash_entry   * e;                                                    i
  177.   int                   b[z];     buffer for statistics
  178.   z         size of b
  179.   char                * s;        symbol string (address) [ key ]
  180.   char                * v;        value string (address)  [datum]
  181.   boolean               f;        TRUE if we found s in hash table            i
  182.   char                * t;        error string; 0 means OK
  183.   int                   a;        access type [0...n)                         i
  184.  
  185.   c=hash_new       ()             create new hash_control
  186.  
  187.   hash_die         (c)            destroy hash_control (and hash table)
  188.   table should be empty.
  189.   doesn't check if table is empty.
  190.   c has no meaning after this.
  191.  
  192.   hash_say         (c,b,z)        report statistics of hash_control.
  193.   also report number of available statistics.
  194.  
  195.   v=hash_delete    (c,s)          delete symbol, return old value if any.
  196.   ask()                       NULL means no old value.
  197.   f
  198.  
  199.   v=hash_replace   (c,s,v)        replace old value of s with v.
  200.   ask()                       NULL means no old value: no table change.
  201.   f
  202.  
  203.   t=hash_insert    (c,s,v)        insert (s,v) in c.
  204.   ask()                       return error string.
  205.   f                           it is an error to insert if s is already
  206.   in table.
  207.   if any error, c is unchanged.
  208.  
  209.   t=hash_jam       (c,s,v)        assert that new value of s will be v.       i
  210.   ask()                       it may decide to GROW the table.            i
  211.   f                                                                       i
  212.   grow()                                                                  i
  213.   t=hash_grow      (c)            grow the hash table.                        i
  214.   jam()                       will invoke JAM.                            i
  215.  
  216.   ?=hash_apply     (c,y)          apply y() to every symbol in c.
  217.   y                           evtries visited in 'unspecified' order.
  218.  
  219.   v=hash_find      (c,s)          return value of s, or NULL if s not in c.
  220.   ask()
  221.   f
  222.  
  223.   f,e=hash_ask()   (c,s,a)        return slot where s SHOULD live.            i
  224.   code()                      maintain collision stats in c.              i
  225.  
  226.   .=hash_code      (c,s)          compute hash-code for s,                    i
  227.   from parameters of c.                       i
  228.  
  229.   */
  230.  
  231. /* Returned by hash_ask() to stop extra testing. hash_ask() wants to
  232.    return both a slot and a status. This is the status.  TRUE: found
  233.    symbol FALSE: absent: empty or deleted slot Also returned by
  234.    hash_jam().  TRUE: we replaced a value FALSE: we inserted a value.  */
  235. static char hash_found;
  236.  
  237. static struct hash_entry *hash_ask PARAMS ((struct hash_control *,
  238.                         const char *, int));
  239. static int hash_code PARAMS ((struct hash_control *, const char *));
  240. static const char *hash_grow PARAMS ((struct hash_control *));
  241.  
  242. /* Create a new hash table.  Return NULL if failed; otherwise return handle
  243.    (address of struct hash).  */
  244. struct hash_control *
  245. hash_new ()
  246. {
  247.   struct hash_control *retval;
  248.   struct hash_entry *room;    /* points to hash table */
  249.   struct hash_entry *wall;
  250.   struct hash_entry *entry;
  251.   int *ip;        /* scan stats block of struct hash_control */
  252.   int *nd;        /* limit of stats block */
  253.  
  254.   room = (struct hash_entry *) xmalloc (sizeof (struct hash_entry)
  255.                     /* +1 for the wall entry */
  256.                     * ((1 << START_POWER) + 1));
  257.   retval = (struct hash_control *) xmalloc (sizeof (struct hash_control));
  258.  
  259.   nd = retval->hash_stat + STATLENGTH;
  260.   for (ip = retval->hash_stat; ip < nd; ip++)
  261.     *ip = 0;
  262.  
  263.   retval->hash_stat[STAT_SIZE] = 1 << START_POWER;
  264.   retval->hash_mask = (1 << START_POWER) - 1;
  265.   retval->hash_sizelog = START_POWER;
  266.   /* works for 1's compl ok */
  267.   retval->hash_where = room;
  268.   retval->hash_wall =
  269.     wall = room + (1 << START_POWER);
  270.   retval->hash_full = (1 << START_POWER) / 2;
  271.   for (entry = room; entry <= wall; entry++)
  272.     entry->hash_string = NULL;
  273.   return retval;
  274. }
  275.  
  276. /*
  277.  *           h a s h _ d i e ( )
  278.  *
  279.  * Table should be empty, but this is not checked.
  280.  * To empty the table, try hash_apply()ing a symbol deleter.
  281.  * Return to free memory both the hash table and it's control
  282.  * block.
  283.  * 'handle' has no meaning after this function.
  284.  * No errors are recoverable.
  285.  */
  286. void
  287. hash_die (handle)
  288.      struct hash_control *handle;
  289. {
  290.   free ((char *) handle->hash_where);
  291.   free ((char *) handle);
  292. }
  293.  
  294. /*
  295.  *           h a s h _ s a y ( )
  296.  *
  297.  * Return the size of the statistics table, and as many statistics as
  298.  * we can until either (a) we have run out of statistics or (b) caller
  299.  * has run out of buffer.
  300.  * NOTE: hash_say treats all statistics alike.
  301.  * These numbers may change with time, due to insertions, deletions
  302.  * and expansions of the table.
  303.  * The first "statistic" returned is the length of hash_stat[].
  304.  * Then contents of hash_stat[] are read out (in ascending order)
  305.  * until your buffer or hash_stat[] is exausted.
  306.  */
  307. void
  308. hash_say (handle, buffer, bufsiz)
  309.      struct hash_control *handle;
  310.      int buffer[ /*bufsiz*/ ];
  311.      int bufsiz;
  312. {
  313.   int *nd;        /* limit of statistics block */
  314.   int *ip;        /* scan statistics */
  315.  
  316.   ip = handle->hash_stat;
  317.   nd = ip + min (bufsiz - 1, STATLENGTH);
  318.   if (bufsiz > 0)        /* trust nothing! bufsiz<=0 is dangerous */
  319.     {
  320.       *buffer++ = STATLENGTH;
  321.       for (; ip < nd; ip++, buffer++)
  322.     {
  323.       *buffer = *ip;
  324.     }
  325.     }
  326. }
  327.  
  328. /*
  329.  *           h a s h _ d e l e t e ( )
  330.  *
  331.  * Try to delete a symbol from the table.
  332.  * If it was there, return its value (and adjust STAT_USED).
  333.  * Otherwise, return NULL.
  334.  * Anyway, the symbol is not present after this function.
  335.  *
  336.  */
  337. PTR                /* NULL if string not in table, else */
  338. /* returns value of deleted symbol */
  339. hash_delete (handle, string)
  340.      struct hash_control *handle;
  341.      const char *string;
  342. {
  343.   PTR retval;
  344.   struct hash_entry *entry;
  345.  
  346.   entry = hash_ask (handle, string, STAT__WRITE);
  347.   if (hash_found)
  348.     {
  349.       retval = entry->hash_value;
  350.       entry->hash_string = DELETED;
  351.       handle->hash_stat[STAT_USED] -= 1;
  352. #ifdef SUSPECT
  353.       if (handle->hash_stat[STAT_USED] < 0)
  354.     {
  355.       error ("hash_delete");
  356.     }
  357. #endif /* def SUSPECT */
  358.     }
  359.   else
  360.     {
  361.       retval = NULL;
  362.     }
  363.   return (retval);
  364. }
  365.  
  366. /*
  367.  *                   h a s h _ r e p l a c e ( )
  368.  *
  369.  * Try to replace the old value of a symbol with a new value.
  370.  * Normally return the old value.
  371.  * Return NULL and don't change the table if the symbol is not already
  372.  * in the table.
  373.  */
  374. PTR
  375. hash_replace (handle, string, value)
  376.      struct hash_control *handle;
  377.      const char *string;
  378.      PTR value;
  379. {
  380.   struct hash_entry *entry;
  381.   char *retval;
  382.  
  383.   entry = hash_ask (handle, string, STAT__WRITE);
  384.   if (hash_found)
  385.     {
  386.       retval = entry->hash_value;
  387.       entry->hash_value = value;
  388.     }
  389.   else
  390.     {
  391.       retval = NULL;
  392.     }
  393.   ;
  394.   return retval;
  395. }
  396.  
  397. /*
  398.  *                   h a s h _ i n s e r t ( )
  399.  *
  400.  * Insert a (symbol-string, value) into the hash table.
  401.  * Return an error string, 0 means OK.
  402.  * It is an 'error' to insert an existing symbol.
  403.  */
  404.  
  405. const char *            /* return error string */
  406. hash_insert (handle, string, value)
  407.      struct hash_control *handle;
  408.      const char *string;
  409.      PTR value;
  410. {
  411.   struct hash_entry *entry;
  412.   const char *retval;
  413.  
  414.   retval = 0;
  415.   if (handle->hash_stat[STAT_USED] > handle->hash_full)
  416.     {
  417.       retval = hash_grow (handle);
  418.     }
  419.   if (!retval)
  420.     {
  421.       entry = hash_ask (handle, string, STAT__WRITE);
  422.       if (hash_found)
  423.     {
  424.       retval = "exists";
  425.     }
  426.       else
  427.     {
  428.       entry->hash_value = value;
  429.       entry->hash_string = string;
  430.       handle->hash_stat[STAT_USED] += 1;
  431.     }
  432.     }
  433.   return retval;
  434. }
  435.  
  436. /*
  437.  *               h a s h _ j a m ( )
  438.  *
  439.  * Regardless of what was in the symbol table before, after hash_jam()
  440.  * the named symbol has the given value. The symbol is either inserted or
  441.  * (its value is) relpaced.
  442.  * An error message string is returned, 0 means OK.
  443.  *
  444.  * WARNING: this may decide to grow the hashed symbol table.
  445.  * To do this, we call hash_grow(), WHICH WILL recursively CALL US.
  446.  *
  447.  * We report status internally: hash_found is TRUE if we replaced, but
  448.  * false if we inserted.
  449.  */
  450. const char *
  451. hash_jam (handle, string, value)
  452.      struct hash_control *handle;
  453.      const char *string;
  454.      PTR value;
  455. {
  456.   const char *retval;
  457.   struct hash_entry *entry;
  458.  
  459.   retval = 0;
  460.   if (handle->hash_stat[STAT_USED] > handle->hash_full)
  461.     {
  462.       retval = hash_grow (handle);
  463.     }
  464.   if (!retval)
  465.     {
  466.       entry = hash_ask (handle, string, STAT__WRITE);
  467.       if (!hash_found)
  468.     {
  469.       entry->hash_string = string;
  470.       handle->hash_stat[STAT_USED] += 1;
  471.     }
  472.       entry->hash_value = value;
  473.     }
  474.   return retval;
  475. }
  476.  
  477. /*
  478.  *               h a s h _ g r o w ( )
  479.  *
  480.  * Grow a new (bigger) hash table from the old one.
  481.  * We choose to double the hash table's size.
  482.  * Return a human-scrutible error string: 0 if OK.
  483.  * Warning! This uses hash_jam(), which had better not recurse
  484.  * back here! Hash_jam() conditionally calls us, but we ALWAYS
  485.  * call hash_jam()!
  486.  * Internal.
  487.  */
  488. static const char *
  489. hash_grow (handle)        /* make a hash table grow */
  490.      struct hash_control *handle;
  491. {
  492.   struct hash_entry *newwall;
  493.   struct hash_entry *newwhere;
  494.   struct hash_entry *newtrack;
  495.   struct hash_entry *oldtrack;
  496.   struct hash_entry *oldwhere;
  497.   struct hash_entry *oldwall;
  498.   int temp;
  499.   int newsize;
  500.   const char *string;
  501.   const char *retval;
  502. #ifdef SUSPECT
  503.   int oldused;
  504. #endif
  505.  
  506.   /*
  507.    * capture info about old hash table
  508.    */
  509.   oldwhere = handle->hash_where;
  510.   oldwall = handle->hash_wall;
  511. #ifdef SUSPECT
  512.   oldused = handle->hash_stat[STAT_USED];
  513. #endif
  514.   /*
  515.    * attempt to get enough room for a hash table twice as big
  516.    */
  517.   temp = handle->hash_stat[STAT_SIZE];
  518.   if ((newwhere = ((struct hash_entry *)
  519.            xmalloc ((unsigned long) ((temp + temp + 1)
  520.                          * sizeof (struct hash_entry)))))
  521.       != NULL)
  522.     /* +1 for wall slot */
  523.     {
  524.       retval = 0;        /* assume success until proven otherwise */
  525.       /*
  526.        * have enough room: now we do all the work.
  527.        * double the size of everything in handle,
  528.        * note: hash_mask frob works for 1's & for 2's complement machines
  529.        */
  530.       handle->hash_mask = handle->hash_mask + handle->hash_mask + 1;
  531.       handle->hash_stat[STAT_SIZE] <<= 1;
  532.       newsize = handle->hash_stat[STAT_SIZE];
  533.       handle->hash_where = newwhere;
  534.       handle->hash_full <<= 1;
  535.       handle->hash_sizelog += 1;
  536.       handle->hash_stat[STAT_USED] = 0;
  537.       handle->hash_wall =
  538.     newwall = newwhere + newsize;
  539.       /*
  540.        * set all those pesky new slots to vacant.
  541.        */
  542.       for (newtrack = newwhere; newtrack <= newwall; newtrack++)
  543.     {
  544.       newtrack->hash_string = NULL;
  545.     }
  546.       /*
  547.        * we will do a scan of the old table, the hard way, using the
  548.        * new control block to re-insert the data into new hash table.
  549.        */
  550.       handle->hash_stat[STAT_USED] = 0;    /* inserts will bump it up to correct */
  551.       for (oldtrack = oldwhere; oldtrack < oldwall; oldtrack++)
  552.     if (((string = oldtrack->hash_string) != NULL) && string != DELETED)
  553.       if ((retval = hash_jam (handle, string, oldtrack->hash_value)))
  554.         break;
  555.  
  556. #ifdef SUSPECT
  557.       if (!retval && handle->hash_stat[STAT_USED] != oldused)
  558.     {
  559.       retval = "hash_used";
  560.     }
  561. #endif
  562.       if (!retval)
  563.     {
  564.       /*
  565.        * we have a completely faked up control block.
  566.        * return the old hash table.
  567.        */
  568.       free ((char *) oldwhere);
  569.       /*
  570.        * Here with success. retval is already 0.
  571.        */
  572.     }
  573.     }
  574.   else
  575.     {
  576.       retval = "no room";
  577.     }
  578.   return retval;
  579. }
  580.  
  581. /*
  582.  *          h a s h _ a p p l y ( )
  583.  *
  584.  * Use this to scan each entry in symbol table.
  585.  * For each symbol, this calls (applys) a nominated function supplying the
  586.  * symbol's value (and the symbol's name).
  587.  * The idea is you use this to destroy whatever is associted with
  588.  * any values in the table BEFORE you destroy the table with hash_die.
  589.  * Of course, you can use it for other jobs; whenever you need to
  590.  * visit all extant symbols in the table.
  591.  *
  592.  * We choose to have a call-you-back idea for two reasons:
  593.  *  asthetic: it is a neater idea to use apply than an explicit loop
  594.  *  sensible: if we ever had to grow the symbol table (due to insertions)
  595.  *            then we would lose our place in the table when we re-hashed
  596.  *            symbols into the new table in a different order.
  597.  *
  598.  * The order symbols are visited depends entirely on the hashing function.
  599.  * Whenever you insert a (symbol, value) you risk expanding the table. If
  600.  * you do expand the table, then the hashing function WILL change, so you
  601.  * MIGHT get a different order of symbols visited. In other words, if you
  602.  * want the same order of visiting symbols as the last time you used
  603.  * hash_apply() then you better not have done any hash_insert()s or
  604.  * hash_jam()s since the last time you used hash_apply().
  605.  *
  606.  * In future we may use the value returned by your nominated function.
  607.  * One idea is to abort the scan if, after applying the function to a
  608.  * certain node, the function returns a certain code.
  609.  * To be safe, please make your functions of type char *. If you always
  610.  * return NULL, then the scan will complete, visiting every symbol in
  611.  * the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet!
  612.  * Caveat Actor!
  613.  *
  614.  * The function you supply should be of the form:
  615.  *      char * myfunct(string,value)
  616.  *              char * string;        |* the symbol's name *|
  617.  *              char * value;         |* the symbol's value *|
  618.  *      {
  619.  *        |* ... *|
  620.  *        return(NULL);
  621.  *      }
  622.  *
  623.  * The returned value of hash_apply() is (char*)NULL. In future it may return
  624.  * other values. NULL means "completed scan OK". Other values have no meaning
  625.  * yet. (The function has no graceful failures.)
  626.  */
  627. char *
  628. hash_apply (handle, function)
  629.      struct hash_control *handle;
  630.      char *(*function) ();
  631. {
  632.   struct hash_entry *entry;
  633.   struct hash_entry *wall;
  634.  
  635.   wall = handle->hash_wall;
  636.   for (entry = handle->hash_where; entry < wall; entry++)
  637.     {
  638.       if (islive (entry))    /* silly code: tests entry->string twice! */
  639.     {
  640.       (*function) (entry->hash_string, entry->hash_value);
  641.     }
  642.     }
  643.   return (NULL);
  644. }
  645.  
  646. /*
  647.  *          h a s h _ f i n d ( )
  648.  *
  649.  * Given symbol string, find value (if any).
  650.  * Return found value or NULL.
  651.  */
  652. PTR
  653. hash_find (handle, string)
  654.      struct hash_control *handle;
  655.      const char *string;
  656. {
  657.   struct hash_entry *entry;
  658.  
  659.   entry = hash_ask (handle, string, STAT__READ);
  660.   if (hash_found)
  661.     return entry->hash_value;
  662.   else
  663.     return NULL;
  664. }
  665.  
  666. /*
  667.  *          h a s h _ a s k ( )
  668.  *
  669.  * Searches for given symbol string.
  670.  * Return the slot where it OUGHT to live. It may be there.
  671.  * Return hash_found: TRUE only if symbol is in that slot.
  672.  * Access argument is to help keep statistics in control block.
  673.  * Internal.
  674.  */
  675. static struct hash_entry *    /* string slot, may be empty or deleted */
  676. hash_ask (handle, string, access)
  677.      struct hash_control *handle;
  678.      const char *string;
  679.      int access;        /* access type */
  680. {
  681.   const char *string1;    /* JF avoid strcmp calls */
  682.   const char *s;
  683.   int c;
  684.   struct hash_entry *slot;
  685.   int collision;    /* count collisions */
  686.  
  687.   /* start looking here */
  688.   slot = handle->hash_where + hash_code (handle, string);
  689.  
  690.   handle->hash_stat[STAT_ACCESS + access] += 1;
  691.   collision = 0;
  692.   hash_found = FALSE;
  693.   while (((s = slot->hash_string) != NULL) && s != DELETED)
  694.     {
  695.       for (string1 = string;;)
  696.     {
  697.       if ((c = *s++) == 0)
  698.         {
  699.           if (!*string1)
  700.         hash_found = TRUE;
  701.           break;
  702.         }
  703.       if (*string1++ != c)
  704.         break;
  705.     }
  706.       if (hash_found)
  707.     break;
  708.       collision++;
  709.       slot++;
  710.     }
  711.   /*
  712.    * slot:                                                      return:
  713.    *       in use:     we found string                           slot
  714.    *       at empty:
  715.    *                   at wall:        we fell off: wrap round   ????
  716.    *                   in table:       dig here                  slot
  717.    *       at DELETED: dig here                                  slot
  718.    */
  719.   if (slot == handle->hash_wall)
  720.     {
  721.       slot = handle->hash_where;/* now look again */
  722.       while (((s = slot->hash_string) != NULL) && s != DELETED)
  723.     {
  724.       for (string1 = string; *s; string1++, s++)
  725.         {
  726.           if (*string1 != *s)
  727.         break;
  728.         }
  729.       if (*s == *string1)
  730.         {
  731.           hash_found = TRUE;
  732.           break;
  733.         }
  734.       collision++;
  735.       slot++;
  736.     }
  737.       /*
  738.        * slot:                                                   return:
  739.        *       in use: we found it                                slot
  740.        *       empty:  wall:         ERROR IMPOSSIBLE             !!!!
  741.        *               in table:     dig here                     slot
  742.        *       DELETED:dig here                                   slot
  743.        */
  744.     }
  745.   handle->hash_stat[STAT_COLLIDE + access] += collision;
  746.   return (slot);        /* also return hash_found */
  747. }
  748.  
  749. /*
  750.  *           h a s h _ c o d e
  751.  *
  752.  * Does hashing of symbol string to hash number.
  753.  * Internal.
  754.  */
  755. static int
  756. hash_code (handle, string)
  757.      struct hash_control *handle;
  758.      const char *string;
  759. {
  760.   long h;        /* hash code built here */
  761.   long c;        /* each character lands here */
  762.   int n;        /* Amount to shift h by */
  763.  
  764.   n = (handle->hash_sizelog - 3);
  765.   h = 0;
  766.   while ((c = *string++) != 0)
  767.     {
  768.       h += c;
  769.       h = (h << 3) + (h >> n) + c;
  770.     }
  771.   return (h & handle->hash_mask);
  772. }
  773.  
  774. /*
  775.  * Here is a test program to exercise above.
  776.  */
  777. #ifdef TEST
  778.  
  779. #define TABLES (6)        /* number of hash tables to maintain */
  780. /* (at once) in any testing */
  781. #define STATBUFSIZE (12)    /* we can have 12 statistics */
  782.  
  783. int statbuf[STATBUFSIZE];    /* display statistics here */
  784. char answer[100];        /* human farts here */
  785. char *hashtable[TABLES];    /* we test many hash tables at once */
  786. char *h;            /* points to curent hash_control */
  787. char **pp;
  788. char *p;
  789. char *name;
  790. char *value;
  791. int size;
  792. int used;
  793. char command;
  794. int number;            /* number 0:TABLES-1 of current hashed */
  795. /* symbol table */
  796.  
  797. main ()
  798. {
  799.   char (*applicatee ());
  800.   char *destroy ();
  801.   char *what ();
  802.   int *ip;
  803.  
  804.   number = 0;
  805.   h = 0;
  806.   printf ("type h <RETURN> for help\n");
  807.   for (;;)
  808.     {
  809.       printf ("hash_test command: ");
  810.       gets (answer);
  811.       command = answer[0];
  812.       if (isupper (command))
  813.     command = tolower (command);    /* ecch! */
  814.       switch (command)
  815.     {
  816.     case '#':
  817.       printf ("old hash table #=%d.\n", number);
  818.       whattable ();
  819.       break;
  820.     case '?':
  821.       for (pp = hashtable; pp < hashtable + TABLES; pp++)
  822.         {
  823.           printf ("address of hash table #%d control block is %xx\n"
  824.               ,pp - hashtable, *pp);
  825.         }
  826.       break;
  827.     case 'a':
  828.       hash_apply (h, applicatee);
  829.       break;
  830.     case 'd':
  831.       hash_apply (h, destroy);
  832.       hash_die (h);
  833.       break;
  834.     case 'f':
  835.       p = hash_find (h, name = what ("symbol"));
  836.       printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT");
  837.       break;
  838.     case 'h':
  839.       printf ("# show old, select new default hash table number\n");
  840.       printf ("? display all hashtable control block addresses\n");
  841.       printf ("a apply a simple display-er to each symbol in table\n");
  842.       printf ("d die: destroy hashtable\n");
  843.       printf ("f find value of nominated symbol\n");
  844.       printf ("h this help\n");
  845.       printf ("i insert value into symbol\n");
  846.       printf ("j jam value into symbol\n");
  847.       printf ("n new hashtable\n");
  848.       printf ("r replace a value with another\n");
  849.       printf ("s say what %% of table is used\n");
  850.       printf ("q exit this program\n");
  851.       printf ("x delete a symbol from table, report its value\n");
  852.       break;
  853.     case 'i':
  854.       p = hash_insert (h, name = what ("symbol"), value = what ("value"));
  855.       if (p)
  856.         {
  857.           printf ("symbol=\"%s\"  value=\"%s\"  error=%s\n", name, value,
  858.               p);
  859.         }
  860.       break;
  861.     case 'j':
  862.       p = hash_jam (h, name = what ("symbol"), value = what ("value"));
  863.       if (p)
  864.         {
  865.           printf ("symbol=\"%s\"  value=\"%s\"  error=%s\n", name, value, p);
  866.         }
  867.       break;
  868.     case 'n':
  869.       h = hashtable[number] = (char *) hash_new ();
  870.       break;
  871.     case 'q':
  872.       exit (EXIT_SUCCESS);
  873.     case 'r':
  874.       p = hash_replace (h, name = what ("symbol"), value = what ("value"));
  875.       printf ("old value was \"%s\"\n", p ? p : "{}");
  876.       break;
  877.     case 's':
  878.       hash_say (h, statbuf, STATBUFSIZE);
  879.       for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++)
  880.         {
  881.           printf ("%d ", *ip);
  882.         }
  883.       printf ("\n");
  884.       break;
  885.     case 'x':
  886.       p = hash_delete (h, name = what ("symbol"));
  887.       printf ("old value was \"%s\"\n", p ? p : "{}");
  888.       break;
  889.     default:
  890.       printf ("I can't understand command \"%c\"\n", command);
  891.       break;
  892.     }
  893.     }
  894. }
  895.  
  896. char *
  897. what (description)
  898.      char *description;
  899. {
  900.   char *retval;
  901.   char *malloc ();
  902.  
  903.   printf ("   %s : ", description);
  904.   gets (answer);
  905.   /* will one day clean up answer here */
  906.   retval = malloc (strlen (answer) + 1);
  907.   if (!retval)
  908.     {
  909.       error ("room");
  910.     }
  911.   (void) strcpy (retval, answer);
  912.   return (retval);
  913. }
  914.  
  915. char *
  916. destroy (string, value)
  917.      char *string;
  918.      char *value;
  919. {
  920.   free (string);
  921.   free (value);
  922.   return (NULL);
  923. }
  924.  
  925.  
  926. char *
  927. applicatee (string, value)
  928.      char *string;
  929.      char *value;
  930. {
  931.   printf ("%.20s-%.20s\n", string, value);
  932.   return (NULL);
  933. }
  934.  
  935. whattable ()            /* determine number: what hash table to use */
  936.      /* also determine h: points to hash_control */
  937. {
  938.  
  939.   for (;;)
  940.     {
  941.       printf ("   what hash table (%d:%d) ?  ", 0, TABLES - 1);
  942.       gets (answer);
  943.       sscanf (answer, "%d", &number);
  944.       if (number >= 0 && number < TABLES)
  945.     {
  946.       h = hashtable[number];
  947.       if (!h)
  948.         {
  949.           printf ("warning: current hash-table-#%d. has no hash-control\n", number);
  950.         }
  951.       return;
  952.     }
  953.       else
  954.     {
  955.       printf ("invalid hash table number: %d\n", number);
  956.     }
  957.     }
  958. }
  959.  
  960.  
  961.  
  962. #endif /* #ifdef TEST */
  963.  
  964. /* end of hash.c */
  965.